home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume5 / xenix.w < prev    next >
Encoding:
Text File  |  1989-02-03  |  13.4 KB  |  541 lines

  1. Path: xanth!mcnc!rutgers!ukma!cwjcc!hal!ncoast!allbery
  2. From: jfh@rpp386.UUCP (The Beach Bum)
  3. Newsgroups: comp.sources.misc
  4. Subject: v05i061: "w" for Xenix/386
  5. Message-ID: <8807130000.AA13905@rpp386.UUCP>
  6. Date: 26 Nov 88 23:17:38 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: jfh@rpp386.UUCP (The Beach Bum)
  9. Lines: 529
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 5, Issue 61
  13. Submitted-by: "The Beach Bum" <jfh@rpp386.UUCP>
  14. Archive-name: xenix.w
  15.  
  16. [This has been waiting for me to fold it into the main "w" code; I've finally
  17. admitted that it isn't going to happen anytime soon, so here it is.  Sigh.
  18. ++bsa]
  19.  
  20. i have hacked the hell out of your "w" command to produce one which
  21. works on sco xenix for a '386.  i don't know what order you will
  22. receive the submissions in, but this is one of two.  the other is
  23. a fuser command.  oh yes, both of them need to be re-wrapped because
  24. my shar doesn't know about the perils of being mailed about.
  25.  
  26. - john.    (jfh@rpp386)
  27. --- beginning for w.shar ---
  28. #! /bin/sh
  29. # This is a shell archive, meaning:
  30. # 1. Remove everything above the #! /bin/sh line.
  31. # 2. Save the resulting text in a file.
  32. # 3. Execute the file with /bin/sh (not csh) to create:
  33. #    README
  34. #    w.1l
  35. #    w.c
  36. # This archive created: Fri Jul  8 09:15:25 1988
  37. # By:    The Beach Bum (Big "D" Home for Wayward Hackers)
  38. export PATH; PATH=/bin:/usr/bin:$PATH
  39. if test -f 'README'
  40. then
  41.     echo shar: "will not over-write existing file 'README'"
  42. else
  43. cat << \SHAR_EOF > 'README'
  44. [ This is the original README which was included with this package.  Note
  45.   that only "w" works.  "avenrun" depends on system statistics which are
  46.   not present in Xenix, and "csl" depends, in part, on "avenrun". -jfh ]
  47.  
  48. The following are some programs which give you some familiar BSD utilities
  49. in a System V environment.  The programs are:
  50.  
  51.        w       - Yes, "w", as big as life!  Requires...
  52.        avenrun - A program to be invoked in /etc/rc which computes
  53.                  a "load average" from information in the "sysinfo"
  54.                  structure of the kernel.  Based on a program by
  55.                  Phil Budne which forges "rwhod" packets for mixed
  56.                  networks; #define RWHOD for the original program.
  57.        csl     - I have no idea what the BSD "sysline" does, but this
  58.                  is my idea of a status line.  The name stands for
  59.                  "cyclic status line"; it doesn't even attempt to
  60.                  fit everything into one line, instead it cycles
  61.                  through a set of "panels".  See the man page.
  62.                  This also wants "avenrun" to be running.
  63.  
  64. Note that "w" (and ONLY "w") can be compiled for System III or Xenix 3.0;
  65. this is in fact the default, use -DSYS5 to get the full version.
  66.  
  67. No Makefile; the compile commands are trivial:
  68.  
  69.        cc -O -o w w.c -DSYS5           # omit the -DSYS5 for System III
  70.        cc -O -o avenrun avenrun.c      # add -DRWHOD for rwhod forgery
  71.        cc -O -o csl csl.c
  72.  
  73. "w" requires read permission on /dev/kmem, /dev/mem, and /dev/swap.  "avenrun"
  74. requires read permission on /dev/kmem (to read the sysinfo structure).  "csl"
  75. can run as a normal user program.  On tdi2 we keep /dev/*mem and /dev/swap
  76. -r--r----- root/sys and have "avenrun" and "w" setgid sys.
  77.  
  78. If someone wants to tell me what "sysline" under BSD does, I'd be interested
  79. in writing a real one.  But "csl" is everything in one small package, so I
  80. will probably continue to use it.
  81.  
  82. Enjoy!
  83.  
  84. ++Brando
  85. SHAR_EOF
  86. fi
  87. if test -f 'w.1l'
  88. then
  89.     echo shar: "will not over-write existing file 'w.1l'"
  90. else
  91. cat << \SHAR_EOF > 'w.1l'
  92. .TH W 1 local
  93. .SH NAME
  94. w \- display users and processes
  95. .SH SYNOPSIS
  96. .B w
  97. .SH DESCRIPTION
  98. .B W
  99. is a program which displays an "intelligent" listing of the current users,
  100. what they're doing, and how active they are.  There are two basic kinds
  101. of information displayed:  system information and per-user information.
  102. An example is shown below.
  103. .nf
  104.  
  105.  10:55pm  up 2 wks 2 days,  4 users
  106. User     tty       login@  idle   JCPU   PCPU what
  107. rhg      tty6     10:36pm        12:20  12:20 csh
  108. robertd  tty7     10:21pm         9:21   9:21 csh
  109. bobw     tty13    10:26pm       160:35 149:43 rn
  110. allbery  tty15     9:47pm        50:22   0:18 sh
  111.  
  112. .fi
  113. The first line displays the current time, how long the system has been up,
  114. and the number of users.
  115. The other lines display for each user, the user's login name, the
  116. terminal the user is on, the time the user logged in, how long the user has
  117. been idle, the CPU time used by the current program and total CPU for the
  118. login session, and the current program.
  119. .SH FILES
  120. .ta \w'/dev/kmem    'u
  121. /dev/kmem      System memory (the process table)
  122. .br
  123. /dev/mem       In-core program images
  124. .br
  125. /dev/swap      Swapped program images
  126. .br
  127. /dev   Searches for terminals
  128. .br
  129. /etc/utmp      Current system users and boot time
  130. .br
  131. /xenix         System namelist
  132. .DT
  133. .SH NOTES
  134. .B W
  135. displays the process name as shown by
  136. .B ps(1)
  137. without the -f argument.
  138. .SH SEE ALSO
  139. ps(1), who(1).
  140. .SH BUGS
  141. JCPU and current process are both kludges.  The former is really only the
  142. CPU of running programs in the terminal session, as Xenix does not retain
  143. user and system times for all programs in a session; the latter attempts to
  144. disregard background processes, but it is nearly impossible to successfully
  145. determine if a program is in the background or not.  This is exacerbated by
  146. the fact that VAR csh(1)'s, when available, look suspiciously like
  147. background processes because they close their standard input.
  148. .PP
  149. If the user block is demand paged, 
  150. .B w
  151. won't find it; I don't have access to a demand-paged system.
  152. .PP
  153. .B who -u
  154. and
  155. .B w
  156. have different ideas on what constitutes idle time; one uses time of last
  157. input, the other the time of last output.
  158. .PP
  159. It is possible that reading the summarized child's system and user times
  160. would produce a better approximation of JCPU.  This is only likely, however,
  161. if the times are updated recursively.
  162. .PP
  163. Things can change while 
  164. .B w
  165. is running; this occasionally causes the current program to be printed as
  166. "[can't stat]" or as "[interstice]".
  167. .PP
  168. If you want "w" to work correctly, get 4.2BSD.
  169. .PP
  170. It should really take options for the system namelist, memory, and
  171. swap files.
  172. .PP
  173. Because Xenix lacks the appropriate kernel variables, load averages are
  174. not available.
  175. .SH CREDIT
  176. Based on a utility written at the University of California at Berkeley.
  177. Original written by Brandon S. Allbery.
  178. Modified for SCO Xenix 386 by John F. Haugh II (jfh@rpp386).
  179. SHAR_EOF
  180. fi
  181. if test -f 'w.c'
  182. then
  183.     echo shar: "will not over-write existing file 'w.c'"
  184. else
  185. cat << \SHAR_EOF > 'w.c'
  186. /*
  187.  * %W% %E% %U% ncoast!bsa %Z%
  188.  * %Z% Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved %Z%
  189.  *
  190.  *    8-Jul-88 John F. Haugh II (jfh@rpp386)
  191.  *    Major hacks to force to work on SCO Xenix 386
  192.  */
  193.  
  194. #ifndef lint
  195. static char _SccsId[] = "%W% %E% %U% ncoast!bsa %Z%";
  196. static char _CopyRt[] = "%Z% Copyright (C) 1985 by Brandon S. Allbery %Z%";
  197. #endif  lint
  198.  
  199. #include <stdio.h>
  200. #include <time.h>
  201. #include <signal.h>
  202. #include <a.out.h>
  203. #include <sys/types.h>
  204. #include <sys/page.h>
  205. #include <sys/seg.h>
  206. #include <sys/param.h>
  207. #include <sys/var.h>
  208. #include <sys/proc.h>
  209. #include <sys/dir.h>
  210. #include <sys/user.h>
  211. #include <sys/stat.h>
  212. #include <sys/ipc.h>
  213. #include <sys/shm.h>
  214. #include <sys/sysmacros.h>
  215. #include <utmp.h>
  216.  
  217. #define UTMP           "/etc/utmp"
  218. #ifndef KERNEL
  219. #define KERNEL         "/xenix"
  220. #endif
  221. #define KMEM           "/dev/kmem"
  222. #define PMEM           "/dev/mem"
  223. #define SMEM           "/dev/swap"
  224.  
  225. #define MIN            (60)
  226. #define HOUR           (MIN * 60)
  227. #define DAY            (HOUR * 24)
  228. #define WEEK           (DAY * 7)
  229. #define MONTH          (DAY * 30)
  230.  
  231. FILE *kfd;
  232. FILE *mfd;
  233. FILE *sfd;
  234. FILE *utmp;
  235. long nproc;
  236. char _SObuf[BUFSIZ];
  237. daddr_t swplo;
  238. short mypid;
  239.  
  240. struct xlist kernel[] = {
  241.     {0, 0, 0, "_v"},
  242.     {0, 0, 0, "_proc"},
  243.     {0, 0, 0, "_swplo"},
  244.     {0, 0, 0, "_lbolt"},
  245.     {0, 0, 0, (char *) 0},
  246. };
  247.  
  248. char *months[] = {
  249.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  250.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  251. };
  252.  
  253. struct tm *localtime();
  254. char *vtime();
  255. char *uptime();
  256. char *itoa();
  257.  
  258. main() {
  259.     struct utmp user;
  260.     short ucnt;
  261.     long now;
  262.     struct var vars;
  263.     
  264.     setbuf(stdout, _SObuf);
  265.     mypid = getpid();
  266.     time(&now);
  267.     if (xlist(KERNEL, kernel) == -1) {
  268.         perror(KERNEL);
  269.         exit(2);
  270.     }
  271.     if ((utmp = fopen(UTMP, "r")) == NULL) {
  272.         perror(UTMP);
  273.         exit(1);
  274.     }
  275.     ucnt = 0;
  276.     while (fread(&user, sizeof user, 1, utmp) > 0) {
  277.         if (user.ut_type != USER_PROCESS)
  278.             continue;
  279.         ucnt++;
  280.     }
  281.     if (kfd == NULL) {
  282.         if ((kfd = fopen(KMEM, "r")) == NULL) {
  283.             perror(KMEM);
  284.             exit(3);
  285.         }
  286.     }
  287.     fseek(kfd, kernel[0].xl_value, 0);
  288.     fread(&vars, sizeof vars, 1, kfd);
  289.     nproc = vars.v_proc;
  290.     fseek(kfd, kernel[2].xl_value, 0);
  291.     fread(&swplo, sizeof swplo, 1, kfd);
  292.     if (mfd == NULL) {
  293.         if ((mfd = fopen(PMEM, "r")) == NULL) {
  294.             perror(PMEM);
  295.             exit(4);
  296.         }
  297.     }
  298.     if (sfd == NULL) {
  299.         if ((sfd = fopen(SMEM, "r")) == NULL) {
  300.             perror(SMEM);
  301.             exit(5);
  302.         }
  303.     }
  304.     printf(" %s  up%s,  %d users\nUser     tty       login@  idle   JCPU   PCPU what\n", vtime(&now), uptime(), ucnt);
  305.     rewind(utmp);
  306.     while (fread(&user, sizeof user, 1, utmp) > 0) {
  307.         if (user.ut_type != USER_PROCESS)
  308.             continue;
  309.         show(&user);
  310.     }
  311.     fclose(utmp);
  312.     exit(0);
  313. }
  314.  
  315. char *uptime() {
  316.     static char timebuf[128];
  317.     struct proc swapper;
  318.     struct user bootproc;
  319.     long oldpos, now;
  320.     short cnt, ocnt;
  321.     long boottime = 0L;
  322.     
  323.     oldpos = fseek(kfd, 0L, 1);
  324.     fseek(kfd, kernel[3].xl_value, 0);
  325.     fread(&boottime, sizeof boottime, 1, kfd);
  326.     now = boottime / HZ;
  327.  
  328.     if (now < 0L)
  329.         return " with strange clock time";
  330.     timebuf[0] = '\0';
  331.     ocnt = 0;
  332.     cnt = 0;
  333.     while (now >= MONTH) {
  334.         cnt++;
  335.         now -= MONTH;
  336.     }
  337.     if (cnt > 0) {
  338.         strcat(timebuf, itoa(cnt));
  339.         strcat(timebuf, " mon");
  340.         if (cnt > 1)
  341.             strcat(timebuf, "s");
  342.         if (++ocnt == 2)
  343.             return timebuf;
  344.     }
  345.     cnt = 0;
  346.     while (now >= WEEK) {
  347.         cnt++;
  348.         now -= WEEK;
  349.     }
  350.     if (cnt > 0) {
  351.         strcat(timebuf, itoa(cnt));
  352.         strcat(timebuf, " wk");
  353.         if (cnt > 1)
  354.             strcat(timebuf, "s");
  355.         if (++ocnt == 2)
  356.             return timebuf;
  357.     }
  358.     cnt = 0;
  359.     while (now >= DAY) {
  360.         cnt++;
  361.         now -= DAY;
  362.     }
  363.     if (cnt > 0) {
  364.         strcat(timebuf, itoa(cnt));
  365.         strcat(timebuf, " day");
  366.         if (cnt > 1)
  367.             strcat(timebuf, "s");
  368.         if (++ocnt == 2)
  369.             return timebuf;
  370.     }
  371.     cnt = 0;
  372.     while (now >= HOUR) {
  373.         cnt++;
  374.         now -= HOUR;
  375.     }
  376.     if (cnt > 0) {
  377.         strcat(timebuf, itoa(cnt));
  378.         strcat(timebuf, " hr");
  379.         if (cnt > 1)
  380.             strcat(timebuf, "s");
  381.     }
  382.     return timebuf;
  383. }
  384.  
  385. char *itoa(n)
  386. int n; {
  387.     static char buf[20];
  388.     
  389.     sprintf(buf, " %d", n);
  390.     return buf;
  391. }
  392.  
  393. findu (proc, slot, user)
  394. struct    proc    *proc;
  395. int    slot;
  396. struct    user    *user;
  397. {
  398.     struct    proc    *procs = (struct proc *) kernel[1].xl_value;
  399.     long    swapaddr;
  400.     int    i;
  401.  
  402.     if ((proc->p_flag & (SSWAP|SSPART)) || ! (proc->p_flag & SLOAD)) {
  403.         swapaddr = proc->p_addr[0].te_frameno * NBPC;
  404.         if (fseek (sfd, swapaddr, 0) == -1L)
  405.             fprintf (stderr, "error in lseek\n");
  406.         fread (user, sizeof *user, 1, sfd);
  407.     } else {
  408.         if (fseek (mfd, proc->p_addr[0].te_frameno * NBPC, 0) == -1L)
  409.             fprintf (stderr, "error in lseek\n");
  410.         fread (user, sizeof *user, 1, mfd);
  411.     }
  412.     if (user->u_procp - procs == slot)
  413.         return (1);
  414.     else
  415.         return (0);
  416. }
  417.  
  418. show(uinfo)
  419. struct utmp *uinfo;
  420. {
  421.     struct stat sbuf;
  422.     struct proc proc;
  423.     struct user prog;
  424.     char ttydev[16];
  425.     long now, cnt, offset, jcpu;
  426.     short mpid, isswap;
  427.     FILE *ufd;
  428.     
  429.     strcpy(ttydev, "/dev/");
  430.     strncpy(&ttydev[5], uinfo->ut_line, 8);
  431.     ttydev[13] = '\0';
  432.     if (stat(ttydev, &sbuf) != 0) {
  433.         perror(ttydev);
  434.         return;
  435.     }
  436.     time(&now);
  437.     now -= sbuf.st_atime;
  438.     printf("%-8.8s %-8.8s %7s ", uinfo->ut_name, uinfo->ut_line, vtime(&uinfo->ut_time));
  439.     if (now > DAY)
  440.         printf("%4dd", now / DAY);
  441.     else if (now > HOUR)
  442.         printf("%2d:%02d", now / HOUR, (now % HOUR) / 60);
  443.     else if (now > MIN)
  444.         printf("%5d", now / MIN);
  445.     else
  446.         printf("     ");
  447.     putchar(' ');
  448.     mpid = -1;
  449.     jcpu = 0;
  450.     for (cnt = 0; cnt < nproc; cnt++) {
  451.         fseek (kfd, kernel[1].xl_value + (cnt * sizeof proc), 0);
  452.         fread(&proc, sizeof proc, 1, kfd);
  453.         if (proc.p_stat == 0 || proc.p_stat == SZOMB || proc.p_stat == SWAIT)
  454.             continue;
  455.  
  456.         if (findu (&proc, cnt, &prog) == 0)
  457.             continue;
  458.  
  459.         if (prog.u_ttyp == NULL)
  460.             continue;
  461.         if (sbuf.st_rdev != prog.u_ttyd)
  462.             continue;
  463.         jcpu += prog.u_utime + prog.u_stime +
  464.             prog.u_cutime + prog.u_cstime;
  465.         if (proc.p_pid == mypid)
  466.             continue;
  467.         if (proc.p_pid > mpid)
  468.             mpid = proc.p_pid;
  469.     }
  470.     if (mpid == -1)
  471.         printf("[can't stat]");
  472.     else {
  473.         fseek(kfd, kernel[1].xl_value, 0);
  474.         for (cnt = 0; cnt < nproc; cnt++) {
  475.             fread(&proc, sizeof proc, 1, kfd);
  476.             if (proc.p_pid == mpid)
  477.                 break;
  478.         }
  479.         if (proc.p_pid != mpid)
  480.             printf("[interstice]");
  481.         else {
  482.             if (findu (&proc, cnt, &prog) == 0)
  483.                 fprintf (stderr, "can't find parent\n");
  484.  
  485.             printf("%3d:%02d %3d:%02d ",
  486.                 (jcpu / HZ) / MIN, (jcpu / HZ) % MIN,
  487.                 ((prog.u_utime + prog.u_stime) / HZ) / MIN,
  488.                 ((prog.u_utime + prog.u_stime) / HZ) % MIN);
  489.             prog.u_procp = &proc;
  490.             pcmd(&prog);
  491.         }
  492.     }
  493.     putchar('\n');
  494. }
  495.  
  496. char *vtime(when)
  497. long *when; {
  498.     struct tm then, now;
  499.     static char buf[20];
  500.     short hour, min, ampm;
  501.     long clock;
  502.  
  503.     time(&clock);
  504.     now = *localtime(&clock);
  505.     then = *localtime(when);
  506.     if (then.tm_mon != now.tm_mon || then.tm_mday != now.tm_mday) {
  507.         sprintf(buf, "%s %2d", months[then.tm_mon], then.tm_mday);
  508.         return buf;
  509.     }
  510.     min = then.tm_min;
  511.     if (then.tm_hour == 0) {
  512.         ampm = 'a';
  513.         hour = 12;
  514.     }
  515.     else if (then.tm_hour > 0 && then.tm_hour < 12) {
  516.         ampm = 'a';
  517.         hour = then.tm_hour;
  518.     }
  519.     else if (then.tm_hour == 12) {
  520.         ampm = 'p';
  521.         hour = 12;
  522.     }
  523.     else {
  524.         ampm = 'p';
  525.         hour = then.tm_hour - 12;
  526.     }
  527.     sprintf(buf, "%d:%02d%cm", hour, min, ampm);
  528.     return buf;
  529. }
  530.  
  531. pcmd(uinfo)
  532. struct user *uinfo;
  533. {
  534.     /* someday look up the user's command line */
  535.     printf("%-.14s", uinfo->u_comm);
  536. }
  537. SHAR_EOF
  538. fi
  539. exit 0
  540. #    End of shell archive
  541.